﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using RaytracerLib;
using RaytracerLib.Layers;
using RaytracerLib.MathLib;
using RaytracerLib.RenderableObjects;
using RaytracerLib.Postprocessing.LightCorrector;
using RaytracerLib.Resamplers;
using RaytracerLib.Samplers;
using RaytracerLib.Volumes;
using TomanuExtensions;
using RaytracerLib.ShadowTesters;
using RaytracerLib.Attenuations;
using System.Reflection;
using RaytracerLib.Layers.Interpolators;
using RaytracerLib.Layers.OverlayCorrectors;
using RaytracerLib.Lights;
using System.Globalization;
using RaytracerLib.MathLib.Polynomials;
using RaytracerLib.UVMappers;
using RaytracerLib.MathLib.RootFinders;
using YAXLib;
using RaytracerLib.Cameras;
using RaytracerLib.Postprocessing;
using System.Drawing.Drawing2D;
using RaytracerLib.Renderers;
using RaytracerLib.Resamplers.Filters;

namespace Raytracer.Generator
{
    partial class TestScenes
    {
        private static void Generate_1750_2199()
        {
            int index = 1750;
            int[] sampler_subress = new int[] { 1, 2, 3, 7 };

            foreach (var sampler in EnumExtensions.GetValues<SamplerType>())
            {
                var sampler_local = sampler;

                if (!(Sampler.Create(sampler_local) is UniformSampler))
                    continue;

                foreach (int sampler_subres in sampler_subress)
                {
                    int sampler_subres_local = sampler_subres;

                    foreach (var rst in EnumExtensions.GetValues<ResamplerType>())
                    {
                        if (rst == ResamplerType.NetResizer)
                            continue;

                        var rst_local = rst;

                        foreach (var filter in EnumExtensions.GetValues<FilterType>())
                        {
                            var filter_local = filter;

                            if (filter == FilterType.NearestNeighbour)
                                continue;

                            List.Add(new TestScene()
                            {
                                Index = index++,
                                Name = String.Format("{3}_{0}_{1}x{1}_{2}", rst_local.ToString().ToLower(),
                                    sampler_subres_local, filter_local.ToString().ToLower(),
                                    sampler_local.ToString().ToLower()),
                                Path = "Resamplers", 
                                GetScene = () =>
                                {
                                    Scene scene = Scenes.Procedural_Layer();
                                    scene.ActiveCamera.Film.Width = 180;
                                    scene.ActiveCamera.Film.Height = 220;
                                    scene.ActiveCamera.Film.Resampler = Resampler.Create(rst_local);
                                    (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(filter_local);
                                    scene.ActiveCamera.Film.Sampler = Sampler.Create(sampler_local);
                                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = sampler_subres_local;
                                    return scene;
                                }
                            });
                        }
                    }
                }
            }
        }

        private static void Generate_2200_2299()
        {
            int index = 2200;
            int[] sampler_subress = new int[] { 3 };
            int[] resampler_subress = new int[] { 1, 5, 9 };

            foreach (int sampler_subres in sampler_subress)
            {
                int sampler_subres_local = sampler_subres;

                List.Add(new TestScene()
                {
                    Index = index++,
                    Name = String.Format("samples {0}x{0}, exact", sampler_subres_local),
                    Path = "Resamplers", 
                    GetScene = () =>
                    {
                        Scene scene = Scenes.Procedural_Layer();
                        scene.ActiveCamera.Film.Width = 180;
                        scene.ActiveCamera.Film.Height = 220;
                        scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.Exact);
                        (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(FilterType.Lanczos);
                        scene.ActiveCamera.Film.Sampler = Sampler.Create(SamplerType.Jitter);
                        (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = sampler_subres_local;
                        return scene;
                    }
                });

                foreach (int resampler_subres in resampler_subress)
                {
                    int resampler_subres_local = resampler_subres;

                    List.Add(new TestScene()
                    {
                        Index = index++,
                        Name = String.Format("samples {0}x{0}, subres {1}", sampler_subres_local, resampler_subres_local),
                        Path = "Resamplers", 
                        GetScene = () =>
                        {
                            Scene scene = Scenes.Procedural_Layer();
                            scene.ActiveCamera.Film.Width = 180;
                            scene.ActiveCamera.Film.Height = 220;
                            scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.LocalGrid);
                            (scene.ActiveCamera.Film.Resampler as LocalGridResampler).Subresolution =
                                resampler_subres_local;
                            (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(FilterType.Lanczos);
                            scene.ActiveCamera.Film.Sampler = Sampler.Create(SamplerType.Jitter);
                            (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = sampler_subres_local;
                            return scene;
                        }
                    });
                }
            }
        }

        private static void Generate_2300_2349()
        {
            int index = 2300;

            List.Add(new TestScene()
            {
                Index = index++,
                Name = "twist 1",
                Path = "Postprocessors\\Twist", 
                GetScene = () =>
                {
                    Scene scene = Scenes.Sphere_Refraction1();
                    scene.RenderableObjects.Remove("sphere");

                    scene.ActiveCamera.Film.Width = 200;
                    scene.ActiveCamera.Film.Height = 200;
                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

                    TwistEffect twist = new TwistEffect();
                    twist.Angle = 180;
                    twist.CenterX = 0.5;
                    twist.CenterY = 0.5;
                    twist.RadiusX = 0.5;
                    twist.RadiusY = 0.5;
                    scene.ActiveCamera.Film.Postprocessors.Add(twist);
                    return scene;
                }
            });

            List.Add(new TestScene()
            {
                Index = index++,
                Name = "twist 2",
                Path = "Postprocessors\\Twist", 
                GetScene = () =>
                {
                    Scene scene = Scenes.Sphere_Refraction1();
                    scene.RenderableObjects.Remove("sphere");

                    scene.ActiveCamera.Film.Width = 200;
                    scene.ActiveCamera.Film.Height = 200;
                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

                    TwistEffect twist = new TwistEffect();
                    twist.Angle = 300;
                    twist.CenterX = 0.5;
                    twist.CenterY = 0.5;
                    twist.RadiusX = 0.5;
                    twist.RadiusY = 0.5;
                    scene.ActiveCamera.Film.Postprocessors.Add(twist);
                    return scene;
                }
            });

            List.Add(new TestScene()
            {
                Index = index++,
                Name = "twist 3",
                Path = "Postprocessors\\Twist", 
                GetScene = () =>
                {
                    Scene scene = Scenes.Sphere_Refraction1();
                    scene.RenderableObjects.Remove("sphere");

                    scene.ActiveCamera.Film.Width = 200;
                    scene.ActiveCamera.Film.Height = 200;
                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

                    TwistEffect twist = new TwistEffect();
                    twist.Angle = 180;
                    twist.CenterX = 0.3;
                    twist.CenterY = 0.5;
                    twist.RadiusX = 0.25;
                    twist.RadiusY = 0.5;
                    scene.ActiveCamera.Film.Postprocessors.Add(twist);
                    return scene;
                }
            });

            List.Add(new TestScene()
            {
                Index = index++,
                Name = "twist 4",
                Path = "Postprocessors\\Twist", 
                GetScene = () =>
                {
                    Scene scene = Scenes.Sphere_Refraction1();
                    scene.RenderableObjects.Remove("sphere");

                    scene.ActiveCamera.Film.Width = 200;
                    scene.ActiveCamera.Film.Height = 200;
                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

                    TwistEffect twist = new TwistEffect();
                    twist.Angle = 180;
                    twist.CenterX = 0.5;
                    twist.CenterY = 0.25;
                    twist.RadiusX = 0.5;
                    twist.RadiusY = 0.7;
                    scene.ActiveCamera.Film.Postprocessors.Add(twist);
                    return scene;
                }
            });

            List.Add(new TestScene()
            {
                Index = index++,
                Name = "twist 5",
                Path = "Postprocessors\\Twist", 
                GetScene = () =>
                {
                    Scene scene = Scenes.Sphere_Refraction1();
                    scene.RenderableObjects.Remove("sphere");

                    scene.ActiveCamera.Film.Width = 200;
                    scene.ActiveCamera.Film.Height = 200;
                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 1;

                    TwistEffect twist = new TwistEffect();
                    twist.Angle = 180;
                    twist.CenterX = 0;
                    twist.CenterY = 0;
                    twist.RadiusX = 0.5;
                    twist.RadiusY = 0.5;
                    scene.ActiveCamera.Film.Postprocessors.Add(twist);
                    return scene;
                }
            });
        }

        private static void Generate_2350_2499()
        {
            int index = 2350;
            int[] sampler_subress = new int[] { 1, 2, 3, 7 };

            foreach (var sampler in EnumExtensions.GetValues<SamplerType>())
            {
                var sampler_local = sampler;

                if (!(Sampler.Create(sampler_local) is UniformSampler))
                    continue;

                foreach (int sampler_subres in sampler_subress)
                {
                    int sampler_subres_local = sampler_subres;

                    foreach (var im in EnumExtensions.GetValues<InterpolationMode>())
                    {
                        if (im == InterpolationMode.Default)
                            continue;
                        if (im == InterpolationMode.Invalid)
                            continue;

                        var im_local = im;

                        List.Add(new TestScene()
                        {
                            Index = index++,
                            Path = "Resamplers", 
                            Name = String.Format("{3}_{0}_{1}x{1}_{2}", ResamplerType.NetResizer.ToString().ToLower(),
                                sampler_subres_local, im_local.ToString().ToLower(),
                                sampler_local.ToString().ToLower()),
                            GetScene = () =>
                            {
                                Scene scene = Scenes.Procedural_Layer();
                                scene.ActiveCamera.Film.Width = 180;
                                scene.ActiveCamera.Film.Height = 220;
                                scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.NetResizer);
                                (scene.ActiveCamera.Film.Resampler as NetResizerResampler).InterpolationMode = im_local;
                                scene.ActiveCamera.Film.Sampler = Sampler.Create(sampler_local);
                                (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = sampler_subres_local;
                                return scene;
                            }
                        });
                    }
                }
            }
        }

        private static void Generate_2500_2599()
        {
            int index = 2500;
            int[] sampler_subress = new int[] { 1, 2, 3, 7 };

            foreach (int sampler_subres in sampler_subress)
            {
                int sampler_subres_local = sampler_subres;

                foreach (var filter in EnumExtensions.GetValues<FilterType>())
                {
                    var filter_local = filter;

                    if (filter == FilterType.NearestNeighbour)
                        continue;

                    List.Add(new TestScene()
                    {
                        Index = index++,
                        Name = String.Format("{3}_{0}_{1}x{1}_{2}", "exact",
                            sampler_subres_local, filter_local.ToString().ToLower(),
                            "poisson"),
                        Path = "Resamplers", 
                        GetScene = () =>
                        {
                            Scene scene = Scenes.Procedural_Layer();
                            scene.ActiveCamera.Film.Width = 180;
                            scene.ActiveCamera.Film.Height = 220;
                            scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.Exact);
                            (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(filter_local);

                            scene.ActiveCamera.Film.Sampler = Sampler.Create(SamplerType.Poisson);
                            (scene.ActiveCamera.Film.Sampler as PoissonSampler).Repeats = 20;

                            double density;
                            switch (sampler_subres_local)
                            {
                                case 1: density = 1.274; break;
                                case 2: density = 1.795; break;
                                case 3: density = 3.8135; break;
                                case 7: density = 8.89; break;
                                default: throw new NotImplementedException();
                            }

                            (scene.ActiveCamera.Film.Sampler as PoissonSampler).Density = density;

                            return scene;
                        }
                    });
                }
            }
        }

        private static void Generate_2600_2699()
        {
            int index = 2600;
            int[] sampler_subress = new int[] { 1, 2, 3, 7 };
            string[] scales = new string[] { "white", "spray" };

            foreach (var sampler in EnumExtensions.GetValues<SamplerType>())
            {
                var sampler_local = sampler;

                foreach (int sampler_subres in sampler_subress)
                {
                    int sampler_subres_local = sampler_subres;

                    foreach (string scale in scales)
                    {
                        string scale_local = scale;

                        List.Add(new TestScene()
                        {
                            Index = index++,
                            Name = String.Format("samples vizualizer, {2}, {0}, {1}x{1}",
                                sampler_local.ToString().ToLower(), sampler_subres_local, scale_local),
                            Path = "Samplers", 
                            GetScene = () =>
                            {
                                Scene scene = Scenes.Procedural_Layer();
                                scene.RenderOptions.Renderer = Renderer.Create(RendererType.SamplesVisualizer);

                                if (scale_local == "white")
                                    (scene.RenderOptions.Renderer as SamplesVisualizerRenderer).Scale = sampler_subres_local;
                                else
                                    (scene.RenderOptions.Renderer as SamplesVisualizerRenderer).Scale = 25;

                                scene.ActiveCamera.Film.Width = 512;
                                scene.ActiveCamera.Film.Height = 512;

                                scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.Exact);
                                (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(FilterType.Box);

                                scene.ActiveCamera.Film.Sampler = Sampler.Create(sampler_local);

                                if (scene.ActiveCamera.Film.Sampler is UniformSampler)
                                    (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = sampler_subres_local;
                                else if (scene.ActiveCamera.Film.Sampler is LowDiscrepancySequenceSampler)
                                {
                                    (scene.ActiveCamera.Film.Sampler as LowDiscrepancySequenceSampler).Subresolution =
                                        sampler_subres_local;
                                }
                                else
                                {
                                    (scene.ActiveCamera.Film.Sampler as PoissonSampler).Repeats = 20;

                                    double density;
                                    switch (sampler_subres_local)
                                    {
                                        case 1: density = 1.274; break;
                                        case 2: density = 1.795; break;
                                        case 3: density = 3.8135; break;
                                        case 7: density = 8.89; break;
                                        default: throw new NotImplementedException();
                                    }

                                    (scene.ActiveCamera.Film.Sampler as PoissonSampler).Density = density;
                                }
                                return scene;
                            }
                        });
                    }
                }
            }
        }

        private static void Generate_2700_2709()
        {
            int index = 2700;

            foreach (var sampler in EnumExtensions.GetValues<SamplerType>())
            {
                var sampler_local = sampler;

                List.Add(new TestScene()
                {
                    Index = index++,
                    Path = "Samplers", 
                    Name = String.Format("fft samples, {0}, 3x3", sampler_local.ToString().ToLower()),
                    GetScene = () =>
                    {
                        Scene scene = Scenes.Procedural_Layer();
                        scene.RenderOptions.Renderer = Renderer.Create(RendererType.SamplesVisualizer);

                        (scene.RenderOptions.Renderer as SamplesVisualizerRenderer).Scale = 25;

                        scene.ActiveCamera.Film.Width = 512;
                        scene.ActiveCamera.Film.Height = 512;

                        scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.Exact);
                        (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(FilterType.Box);

                        scene.ActiveCamera.Film.Sampler = Sampler.Create(sampler_local);

                        if (scene.ActiveCamera.Film.Sampler is UniformSampler)
                            (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 3;
                        else if (scene.ActiveCamera.Film.Sampler is LowDiscrepancySequenceSampler)
                            (scene.ActiveCamera.Film.Sampler as LowDiscrepancySequenceSampler).Subresolution = 3;
                        else
                        {
                            (scene.ActiveCamera.Film.Sampler as PoissonSampler).Repeats = 20;
                            (scene.ActiveCamera.Film.Sampler as PoissonSampler).Density = 3.8135;
                        }

                        scene.ActiveCamera.Film.Postprocessors.Add(new FFT2Transform());

                        return scene;
                    }
                });
            }
        }

        private static void Generate_2710_2719()
        {
            int index = 2750;

            foreach (var sampler in EnumExtensions.GetValues<SamplerType>())
            {
                var sampler_local = sampler;

                List.Add(new TestScene()
                {
                    Index = index++,
                    Name = String.Format("periodogram, {0}", sampler_local.ToString().ToLower()),
                    Path = "Samplers", 
                    GetScene = () =>
                    {
                        Scene scene = Scenes.Procedural_Layer();
                        scene.RenderOptions.Renderer = Renderer.Create(RendererType.SamplerPeriodogram);

                        (scene.RenderOptions.Renderer as SamplesPeriodogramRenderer).ScaleSamples = 20;
                        (scene.RenderOptions.Renderer as SamplesPeriodogramRenderer).ScaleValues = 0.001;
                        (scene.RenderOptions.Renderer as SamplesPeriodogramRenderer).Repeats = 100;

                        scene.ActiveCamera.Film.Width = 512;
                        scene.ActiveCamera.Film.Height = 512;

                        scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.Exact);
                        (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(FilterType.Box);

                        scene.ActiveCamera.Film.Sampler = Sampler.Create(sampler_local);

                        if (scene.ActiveCamera.Film.Sampler is UniformSampler)
                            (scene.ActiveCamera.Film.Sampler as UniformSampler).Subresolution = 3;
                        else if (scene.ActiveCamera.Film.Sampler is LowDiscrepancySequenceSampler)
                            (scene.ActiveCamera.Film.Sampler as LowDiscrepancySequenceSampler).Subresolution = 3;
                        else
                        {
                            (scene.ActiveCamera.Film.Sampler as PoissonSampler).Repeats = 20;
                            (scene.ActiveCamera.Film.Sampler as PoissonSampler).Density = 3;
                        }

                        return scene;
                    }
                });
            }
        }

        private static void Generate_2900_2999()
        {
            int index = 2900;
            int[] sampler_subress = new int[] { 1, 2, 3, 7 };

            SamplerType[] samplers = new SamplerType[] { SamplerType.Halton, 
                SamplerType.HaltonFolded, SamplerType.Hammersley, SamplerType.HammersleyFolded, SamplerType.Sobol };

            foreach (var sampler in samplers)
            {
                var sampler_local = sampler;

                foreach (int sampler_subres in sampler_subress)
                {
                    int sampler_subres_local = sampler_subres;

                    foreach (var filter in EnumExtensions.GetValues<FilterType>())
                    {
                        var filter_local = filter;

                        if (filter == FilterType.NearestNeighbour)
                            continue;

                        List.Add(new TestScene()
                        {
                            Index = index++,
                            Name = String.Format("{3}_{0}_{1}x{1}_{2}", "exact",
                                sampler_subres_local, filter_local.ToString().ToLower(), sampler_local),
                            Path = "Resamplers", 
                            GetScene = () =>
                            {
                                Scene scene = Scenes.Procedural_Layer();
                                scene.ActiveCamera.Film.Width = 180;
                                scene.ActiveCamera.Film.Height = 220;
                                scene.ActiveCamera.Film.Resampler = Resampler.Create(ResamplerType.Exact);
                                (scene.ActiveCamera.Film.Resampler as FilterResampler).Filter = Filter.Create(filter_local);

                                scene.ActiveCamera.Film.Sampler = Sampler.Create(sampler_local);

                                (scene.ActiveCamera.Film.Sampler as LowDiscrepancySequenceSampler).Subresolution =
                                    sampler_subres_local;

                                return scene;
                            }
                        });
                    }
                }
            }
        }

        private static void Generate_3200_3399()
        {
            Scene[] scenes = new Scene[] 
            { 
                Scenes.Torus(), 
                Scenes.Torus_Refraction(RefractiveIndices.OpticGlass1) 
            };

            string[] scene_names = new string[] 
            { 
                "solid", 
                "refra"
            };

            scenes[0].Lights["light1"].Remove();
            scenes[0].Lights["light2"].Remove();
            scenes[0].Lights["light3"].Remove();
            scenes[0].Lights["light4"].Remove();

            scenes[0].RenderOptions.AmbientColor = ColorFloat.White;
            scenes[0].Materials["blue"].Ambient = null;

            Fast(scenes[0]);
            Fast(scenes[1]);

            scenes[0].ActiveCamera.Pos = new Vector3(0, 0, -3);
            scenes[1].ActiveCamera.Pos = new Vector3(0, 0, -5);

            (scenes[0].ActiveCamera as PerspectiveCamera).MinimalPlaneDistant = 0.1;
            (scenes[1].ActiveCamera as PerspectiveCamera).MinimalPlaneDistant = 0.1;

            scenes[0].Lights["light"].Color = ColorFloat.White;
            scenes[1].Lights["light"].Color = ColorFloat.White;

            Vector3[] lights_pos = new Vector3[] 
            { 
                new Vector3(0, 0, -5), 
                new Vector3(-3, -3, -5) 
            };

            string[] lights_name = new string[] 
            { 
                "central", 
                "side"
            };

            // R / r
            double[] ratios = new double[] { 6, 1.01, 1, 0.9, 0.2, 0.05, 0.001, 0 };

            int index = 3200;

            for (int scene_index = 0; scene_index < scenes.Length; scene_index++)
            {
                int scene_index_loc = scene_index;

                for (int light_index = 0; light_index < lights_pos.Length; light_index++)
                {
                    int light_index_loc = light_index;

                    foreach (var ratio in ratios)
                    {
                        foreach (var rfm in EnumExtensions.GetValues<RootFindingMethod>())
                        {
                            var rfm_local = rfm;

                            double torus_small_radius = 1 / (1 + ratio);
                            double torus_big_radius = 1 / (1 + 1 / ratio);

                            string sn = String.Format("root finder {0} {1} - {2}, {3}",
                                scene_names[scene_index], rfm_local, 
                                ratio.ToString(CultureInfo.InvariantCulture).Replace(",", "."),
                                lights_name[light_index]);

                            List.Add(new TestScene()
                            {
                                Name = sn,
                                Index = index++,
                                Path = "Root finders", 
                                GetScene = () =>
                                {
                                    Scene scene = scenes[scene_index_loc].DeepClone();
                                    Fast(scene);

                                    scene.RenderOptions.PolynomialSolveMethod = PolynomialSolveMethod.Sturm;
                                    scene.RenderOptions.RootFindingMethod = rfm_local;

                                    TorusObject torus = scene.RenderableObjects["torus"] as TorusObject;
                                    torus.RotateAroundRight(90);
                                    torus.SmallRadius = torus_small_radius;
                                    torus.BigRadius = torus_big_radius;

                                    Light light = scene.Lights["light"];
                                    light.Pos = lights_pos[light_index_loc];

                                    scene.Name = sn;


                                    return scene;
                                }
                            });
                        }
                    }
                }
            }
        }

        private static void Generate_4000_4799()
        {
            double STEP = 10;
            Vector3[] dirs = new [] { Vector3.XAXIS, Vector3.YAXIS, Vector3.ZAXIS };
            Vector3[] exps = new [] { new Vector3(0.5, 0.5, 0.5), new Vector3(1, 0.5, 0.5), new Vector3(2.3, 0.5, 1), 
                new Vector3(4.4, 4.2, 0.5), new Vector3(1, 1, 1), new Vector3(2, 2, 2), new Vector3(4.4, 1.6, 0.5) };

            int index = 4000;

            for (int scene_type = 1; scene_type <= 2; scene_type++)
            {
                int scene_type_local = scene_type;

                foreach (var exp in exps)
                {
                    Vector3 exp_local = exp;

                    foreach (var dir in dirs)
                    {
                        var dir_local = dir;

                        for (int angle = 0; angle <= 180 / STEP; angle++)
                        {
                            int angle_local = angle;

                            List.Add(new TestScene()
                            {
                                Name = String.Format("superquadrics {0}, exps ({1}, {2}, {3}), dir {4}, angle {5}",
                                    (scene_type_local == 1) ? "solid" : "refra", 
                                    exp_local.X.ToString().Replace(",", "."), 
                                    exp_local.Y.ToString().Replace(",", "."), 
                                    exp_local.Z.ToString().Replace(",", "."), 
                                    (dir_local == Vector3.XAXIS) ? "X" : (dir_local == Vector3.YAXIS) ? "Y" : "Z", 
                                    (angle_local * STEP).ToString().Replace(",", ".")),
                                Index = index++,
                                Path = "Superquadric", 
                                GetScene = () =>
                                {
                                    Scene scene;

                                    if (scene_type_local == 1)
                                        scene = Scenes.Superquadric();
                                    else
                                        scene = Scenes.Superquadric_Refraction();

                                    Fast(scene);

                                    scene.RenderOptions.PolynomialSolveMethod = PolynomialSolveMethod.Sturm;
                                    scene.RenderOptions.RootFindingMethod = RootFindingMethod.ModifedRegulaFalsi;

                                    SuperquadricObject sq = scene.RenderableObjects["sq"] as SuperquadricObject;
                                    sq.RotateAround(sq.Pos, dir_local, angle_local * STEP);
                                    sq.Exponents = exp_local;

                                    return scene;
                                }
                            });
                        }
                    }
                }
            }
        }

        private static void Generate_4900_4909()
        {
            Vector3[] exps = new[] { new Vector3(0.5, 0.5, 0.5), new Vector3(1, 0.5, 0.5), new Vector3(2.3, 0.5, 1), 
                new Vector3(4.4, 4.2, 0.5), new Vector3(1, 1, 1), new Vector3(4.4, 1.6, 0.5) };

            int index = 4900;

            foreach (var exp in exps)
            {
                Vector3 exp_local = exp;

                List.Add(new TestScene()
                {
                    Name = String.Format("superquadrics {0}, exps ({1}, {2}, {3})",
                        "solid",
                        exp_local.X.ToString().Replace(",", "."),
                        exp_local.Y.ToString().Replace(",", "."),
                        exp_local.Z.ToString().Replace(",", ".")), 
                    Index = index++,
                    Path = "Superquadric",
                    GetScene = () =>
                    {
                        Scene scene = Scenes.Superquadric(); ;
                        Fast(scene);

                        scene.RenderOptions.PolynomialSolveMethod = PolynomialSolveMethod.Sturm;
                        scene.RenderOptions.RootFindingMethod = RootFindingMethod.ModifedRegulaFalsi;

                        SuperquadricObject sq = scene.RenderableObjects["sq"] as SuperquadricObject;
                        sq.RotateAround(sq.Pos, Vector3.XAXIS, 30);
                        sq.RotateAround(sq.Pos, Vector3.YAXIS, 70);
                        sq.RotateAround(sq.Pos, Vector3.ZAXIS, 10);
                        sq.Exponents = exp_local;

                        return scene;
                    }
                });
            }
        }

        private static void Generate_5000_5799()
        {
            double STEP = 10;
            Vector3[] dirs = new[] { Vector3.XAXIS, Vector3.YAXIS, Vector3.ZAXIS };
            double[][] exps = { new[] { 0.5, 0.5 }, new[] { 1, 0.5 }, new[] { 2.3, 0.5 }, new[] { 4.4, 4.2 }, 
                                new[] { 1.0, 1.0 }, new[] { 20.0, 2.0 } };

            int index = 5000;

            for (int scene_type = 1; scene_type <= 2; scene_type++)
            {
                int scene_type_local = scene_type;

                foreach (var exp in exps)
                {
                    double[] exp_local = exp;

                    foreach (var dir in dirs)
                    {
                        var dir_local = dir;

                        for (int angle = 0; angle <= 180 / STEP; angle++)
                        {
                            int angle_local = angle;

                            List.Add(new TestScene()
                            {
                                Name = String.Format("superellipsoid {0}, R {1}, T {2}, dir {3}, angle {4}",
                                    (scene_type_local == 1) ? "solid" : "refra",
                                    exp_local[0].ToString().Replace(",", "."),
                                    exp_local[1].ToString().Replace(",", "."),
                                    (dir_local == Vector3.XAXIS) ? "X" : (dir_local == Vector3.YAXIS) ? "Y" : "Z",
                                    (angle_local * STEP).ToString().Replace(",", ".")),
                                Index = index++,
                                Path = "Superellipsoid",
                                GetScene = () =>
                                {
                                    Scene scene;

                                    if (scene_type_local == 1)
                                        scene = Scenes.Superellipsoid();
                                    else
                                        scene = Scenes.Superellipsoid_Refraction();

                                    Fast(scene);

                                    scene.RenderOptions.PolynomialSolveMethod = PolynomialSolveMethod.Sturm;
                                    scene.RenderOptions.RootFindingMethod = RootFindingMethod.ModifedRegulaFalsi;

                                    SuperellipsoidObject se = scene.RenderableObjects["se"] as SuperellipsoidObject;
                                    se.RotateAround(se.Pos, dir_local, angle_local * STEP);
                                    se.R = exp_local[0];
                                    se.T = exp_local[1];

                                    return scene;
                                }
                            });
                        }
                    }
                }
            }
        }

        private static void Generate_5900_5909()
        {
            Vector3[] exps = new[] { new Vector3(0.5, 0.5, 0.5), new Vector3(1, 0.5, 0.5), new Vector3(2.3, 0.5, 1), 
                new Vector3(4.4, 4.2, 0.5), new Vector3(1, 1, 1), new Vector3(20, 2, 0.5) };

            int index = 5900;

            foreach (var exp in exps)
            {
                Vector3 exp_local = exp;

                List.Add(new TestScene()
                {
                    Name = String.Format("superellipsoid {0}, R {1}, T {2})",
                        "solid",
                        exp_local.X.ToString().Replace(",", "."),
                        exp_local.Y.ToString().Replace(",", ".")), 
                    Index = index++,
                    Path = "Superellipsoid",
                    GetScene = () =>
                    {
                        Scene scene = Scenes.Superellipsoid(); ;
                        Fast(scene);

                        scene.RenderOptions.PolynomialSolveMethod = PolynomialSolveMethod.Sturm;
                        scene.RenderOptions.RootFindingMethod = RootFindingMethod.ModifedRegulaFalsi;

                        SuperellipsoidObject sq = scene.RenderableObjects["se"] as SuperellipsoidObject;
                        sq.RotateAround(sq.Pos, Vector3.XAXIS, 30);
                        sq.RotateAround(sq.Pos, Vector3.YAXIS, 70);
                        sq.RotateAround(sq.Pos, Vector3.ZAXIS, 10);
                        sq.R = exp_local.X;
                        sq.T = exp_local.Y;

                        return scene;
                    }
                });
            }
        }
    }
}